﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NFit.Core.Errors;
using System.Reflection;
using NFit.Core.BaseClasses;

namespace NFit.Core
{
    /// <summary>
    /// Represent the definition of the fixture through a list of rows
    /// </summary>
    public class FixtureDefinition : RunnableActiveList<FixtureRow,AbstractFixture>
    {
        /// <summary>
        /// The description header of the fixture
        /// </summary>
        public string Header { get; set; }

        /// <summary>
        /// The description footer of the fixture
        /// </summary>
        public string Footer { get; set; }        

        /// <summary>
        /// The definition of the cells (used in all table style fixtures)
        /// </summary>
        public FixtureRow Definition { get; set; }
        
        /// <summary>
        /// List of the fixture's rows
        /// </summary>
        public IList<FixtureRow> Rows
        {
            get { return ChildElements; }
        }

        /// <summary>
        /// Validate the fixture (check if it has a valid implementation)
        /// </summary>
        /// <param name="testFixture"></param>
        public void Validate(bool testFixture)
        {
            if (!testFixture)
            {
                if (string.IsNullOrEmpty(ClassName) && ClassType == null)
                {
                    Status.NestedError = ElementNotFoundError.Fixture(null);
                    Status.Success=false;
                }
                if (!string.IsNullOrEmpty(ClassName) && ClassType == null)
                {
                    Status.NestedError = ElementNotFoundError.Fixture(ClassName);
                    Status.Success = false;
                }
            }
        }        

        private FixtureRow AddRow(params string[] Cells)
        {
            FixtureRow rw = new FixtureRow();
            foreach(string s in Cells)
            {
                rw.AddCell(s.Trim());
            }
            return rw;
        }

        private FixtureRow AddRow(params object[] Cells)
        {
            FixtureRow rw = new FixtureRow();
            foreach (object ob in Cells)
            {
                rw.AddCell(ob);
            }
            return rw;
        }

        /// <summary>
        /// Set the fixture header
        /// </summary>
        /// <param name="aHeader">the header</param>
        /// <returns>the fixture</returns>
        public FixtureDefinition WithHeader(string aHeader)
        {
            Header = aHeader;
            return this;
        }

        /// <summary>
        /// Set the fixture footer
        /// </summary>
        /// <param name="aFooter">the footer</param>
        /// <returns>the fixture</returns>
        public FixtureDefinition WithFooter(string aFooter)
        {
            Footer = aFooter;
            return this;
        }

        /// <summary>
        /// Fill the ClassName of the fixture
        /// </summary>
        /// <param name="classname">The name of the fixture's implementation class</param>
        /// <returns></returns>
        public FixtureDefinition WithClass(string classname)
        {
            ClassName = classname;
            return this;
        }

        /// <summary>
        /// Fill the ClassType of the fixture
        /// </summary>
        /// <param name="t">The type of the fixture implementation</param>
        /// <returns></returns>
        public FixtureDefinition WithClass(Type t)
        {
            ClassType = t;
            return this;
        }

        /// <summary>
        /// Add a row with the list of cells text provided
        /// </summary>
        /// <param name="Cells">List of the cells text</param>
        /// <returns>The fixture itself (for method chaining)</returns>
        public FixtureDefinition WithRow(params string[] Cells)
        {
            FixtureRow rw = AddRow(Cells);            
            Add(rw);
            return this;
        }

        /// <summary>
        /// Add a row with the list of expected value provided
        /// </summary>
        /// <param name="Cells"></param>
        /// <returns>The fixture itself (for method chaining)</returns>
        public FixtureDefinition WithRow(params object[] Cells)
        {
            FixtureRow rw = AddRow(Cells);
            Add(rw);
            return this;
        }

        /// <summary>
        /// Add a row definition with the list of cells text provided
        /// </summary>
        /// <param name="Cells">List of definition cells</param>
        /// <returns>The fixture itself (for method chaining)</returns>
        public FixtureDefinition WithDef(params string[] Cells)
        {
            Definition = AddRow(Cells);
            return this;
        }

        /// <summary>
        /// Add a list of arguments
        /// </summary>
        /// <param name="Cells"></param>
        /// <returns>The fixture itself (for method chaining)</returns>
        public FixtureDefinition WithArg(params string[] Cells)
        {
            Arguments = AddRow(Cells);
            return this;
        }                 
    }

    /// <summary>
    /// Generic fixture definition. This class is used in a code context.
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class FixtureDefinition<T> : FixtureDefinition where T:AbstractFixture
    {
        /// <summary>
        /// Constructor
        /// </summary>
        public FixtureDefinition()
        {
            ClassType = typeof (T);
        }
    }
}
